#include "Page.h"
#include <sstream>

Page * Page::newPage(const int32_t pageSize){
    char * addr = (char*)calloc(pageSize, sizeof(char));
    return new Page(1, addr, pageSize);
}
void Page::freePage(Page* page){
    if(page != nullptr){
        free(page->getAddr());
    }
    delete page;
}

template<typename T>
int writeRaw(Page * page, const T raw, const int32_t offset){
    if(page != nullptr){
        if((sizeof(T) + offset) <= page->getSize()){
            *((T*)(page->getAddr() + offset)) = raw;
            return 0;
        }
        return -1; // offset error 
    }
    return -1;
}
int Page::writeByte(char v, const int32_t offset){
    return ::writeRaw(this, v, offset);
}
int Page::writeInt16(int16_t v, const int32_t offset){
    return ::writeRaw(this, v, offset);
}
int Page::writeUint16(uint16_t v, const int32_t offset){
    return ::writeRaw(this, v, offset);
}
int Page::writeInt32(int32_t v, const int32_t offset){
    return ::writeRaw(this, v, offset);
}
int Page::writeUint32(uint32_t v, const int32_t offset){
    return ::writeRaw(this, v, offset);
}
int Page::writeInt64(int64_t v, const int32_t offset){
    return ::writeRaw(this, v, offset);
}
int Page::writeUint64(uint64_t v, const int32_t offset){
    return ::writeRaw(this, v, offset);
}

template<typename T>
int readRaw(const Page * page, const int32_t offset, T * v){
    if(page != nullptr){
        if((sizeof(T) + offset) <= page->getSize()){
            *v = *((T*)(page->getAddr() + offset));
            return 0;
        }
        return -1; // offset error 
    }
    return -1; // page is nullptr
}
int Page::readByte(const int32_t offset, char * v) const{
    return readRaw(this, offset, v);
}
int Page::readInt16(const int32_t offset, int16_t * v) const{
    return readRaw(this, offset, v);
}
int Page::readUint16(const int32_t offset, uint16_t * v) const{
    return readRaw(this, offset, v);
}
int Page::readInt32(const int32_t offset, int32_t * v) const{
    return readRaw(this, offset, v);
}
int Page::readUint32(const int32_t offset, uint32_t * v) const{
    return readRaw(this, offset, v);
}
int Page::readInt64(const int32_t offset, int64_t * v) const{
    return readRaw(this, offset, v);
}
int Page::readUint64(const int32_t offset, uint64_t * v) const{
    return readRaw(this, offset, v);
}

Page::Page(PageNumberType pageNo, char * pageAddr, const int32_t pageSize)
: pageNo(pageNo)
, pageAddr(pageAddr)
, pageSize(pageSize)
, status(Page::Allocated)
{
}
Page::~Page(){
}

int Page::writeBytes(const char * bytes, const int32_t srcLen, const int32_t offset, const int32_t length){
    assert(status >= Page::Allocated);

    assert(bytes != nullptr && srcLen >= 0);
    assert(offset >=0 && offset < pageSize);
    assert(length >= 1 && length <= pageSize);

    if(offset + length <= pageSize){
        if(srcLen >= length){
            memcpy(pageAddr+offset, bytes, length);
            status = Page::Dirty;
            return 0;
        }
        //srcLen <= length, error
    }
    // offset+length overflow
    return -1;
}
std::string Page::hex(const int32_t offset, const int32_t length) const{
    
    if(offset >= 0 && offset < pageSize && (offset + length) <= pageSize){
        std::ostringstream oss;
        int32_t count = offset + length;
        for( int i = offset; i < count ; ++i){
            oss << std::hex << (unsigned short)(pageAddr[i]);
        }
        return oss.str();
    }
    return "argument error!";
}
const std::string Page::toString() const{
    std::ostringstream oss;
    oss << "Page: NO:" << pageNo << "status:" << status;
    return oss.str(); 
}
